/******************************************************************************
 * Student Name: Ofri Keidar
 * Exercise Name: Ex2
 * File Description: Class CourseLinkedList's interface
 ******************************************************************************/

#ifndef COURSELINKEDLIST_H_
#define COURSELINKEDLIST_H_
#include "Course.h"
#include "StudentLinkedList.h"
#include "LecturerLinkedList.h"

#define FIRST_CASE 1 // used to initialize enum type's first value
#define NUMBER_ERROR_VAL -1 // value to indicate error in course number attribute

class CourseLinkedList {

private:
	class Node {

		private:
			/***************************************************************************************
			 * function name: Node(const Node& node)
			 * The Input: Node to be copied
			 * The output: None
			 * The Function operation: The copy constructor is private and an empty-implementation
			 * 			   			   because node objects should not be sent to functions by value
			 ***************************************************************************************/
			Node(const Node& node): m_courseData(node.m_courseData) {}

		public:
			Course* const m_courseData; // pointer to course data
			Node* m_prevNode; // pointer to previous node
			Node* m_nextNode; // pointer to next node
			int m_index; // node's index in list

			/***************************************************************************************
			 * function name: Node (Course* const courseToPoint)
			 * The Input: Course data to point at
			 * The output: None
			 * The Function operation: Creates a new node pointing to given course
			 ***************************************************************************************/
			Node (Course* const courseToPoint);

			/****************************************************************************************
			 * function name: ~Node()
			 * The Input: None
			 * The output: None
			 * The Function operation: Destructs node object
			 ***************************************************************************************/
			~Node();

			/****************************************************************************************
			 * function name: setIndex(const int newIndex)
			 * The Input: New index for node
			 * The output: None
			 * The Function operation: Sets index attribute as given value
			 ***************************************************************************************/
			void setIndex(const int newIndex) {m_index = newIndex;}
	};


	Node* m_headDummy; // pointer to first node on list
	Node* m_tailDummy; // pointer to last node on list
	Node* m_currentNode; // node pointer that the user can change the node that it points at at get it's data
	const StudentLinkedList& m_studentDataBase; // list of all existing students
	const LecturerLinkedList& m_lecturerDataBase; // list of all existing lecturers

	/***************************************************************************************
	 * function name: CourseLinkedList(const CourseLinkedList& list)
	 * The Input: List to be copied
	 * The output: None
	 * The Function operation: The copy constructor is an empty-implementation
	 * 			               because student linked list objects should not be sent to
	 * 			               functions by value
	 ***************************************************************************************/
	CourseLinkedList(const CourseLinkedList& list): m_studentDataBase(list.m_studentDataBase) ,m_lecturerDataBase(list.m_lecturerDataBase) {}

	/***************************************************************************************
	 * function name: findPlace(const Course& newCourse)
	 * The Input: Pointer to the new course
	 * The output: Node pointer to which the new course should be linked.
	 * 			   If a course with new course's number already exists, NULL is returned
	 * The Function operation: The method checks if a course with the new course's number already
	 * 			   exists. If no such course was found, the method returns a
	 * 			   node pointer which before it new course will be linked. Method does
	 * 			   not change list object
	 ***************************************************************************************/
	Node* findPlace(const Course& newCourse) const;

	/***************************************************************************************
	 * function name: internalAdd(Course& newCourse, Node* before)
	 * The Input: Pointer to course to be added and a pointer to the node where the new
	 * 	      course will be linked
	 * The output: None
	 * The Function operation: The method creates a new node pointing to the new course
	 * 			   and links the new node in the given location to the list
	 ***************************************************************************************/
	void internalAdd(Course& newCourse, Node* before);

public:

	enum AddCourseRetVals {
		COURSE_EXISTS = FIRST_CASE,
		NO_SUCH_LECTURER,
		COURSE_ADDED
	}; // Return values for course adding method, used to indicate type of error or success in adding a new course to the list


	/***************************************************************************************
	 * function name: CourseLinkedList(const StudentLinkedList& m_studentDataBase, const LecturerLinkedList& lecturerDataBase)
	 * The Input: None
	 * The output: None
	 * The Function operation: Creates a new course linked list
	 ***************************************************************************************/
	CourseLinkedList(const StudentLinkedList& m_studentDataBase, const LecturerLinkedList& lecturerDataBase);

	/***************************************************************************************
	 * function name: ~CourseLinkedList()
	 * The Input: None
	 * The output: None
	 * The Function operation: Deletes the course linked list and the pointed data.
	 * 						   Students and lecturers data not deleted
	 ***************************************************************************************/
	~CourseLinkedList();

	/***************************************************************************************
	 * function name: AddCourseRetVals addCourse(const int courseNumber, const int lecturerID)
	 * The Input: New course number and new course's lecturer id
	 * The output: COURSE_EXISTS if in course list already exists a course with given course
	 * 			   number, NO_SUCH_LECTURER if there is not a lecturer with given id,
	 * 			   COURSE_ADDED if course was successfully added to course list
	 * The Function operation: If there is already a course with the new course's number,
	 * 			               student is not added and COURSE_EXISTS returned.
	 * 			               Otherwise, it checks in lecturer database if there is a lecturer with given
	 * 			               id. If there is not, course is not added and NO_SUCH_LECTURER returned.
	 * 			               Otherwise it adds the course and keeps the list sorted from lowest course
	 * 			               number to highest
	 ***************************************************************************************/
	AddCourseRetVals addCourse(const int courseNumber, const int lecturerID);

	/***************************************************************************************
	 * function name: addStudentsToCourse(const int courseNumber, const int numOfStudents, int** idList)
	 * The Input: Course number to which students should be added, number of students to add
	 * 			  and a list of their id's
	 * The output: NUMBER_ERROR_VAL if no such course exist or number of students who were
	 * 			   not added
	 * The Function operation: For each given id, if there is not a student with the same
	 * 						   id, it adds the student. idList is a 2-dimensional array
	 * 						   that its first column is idList and the second is adding
	 * 						   result- True if student was added and False if not
	 ***************************************************************************************/
	int addStudentsToCourse(const int courseNumber, const int numOfStudents, int** idList);

	/***************************************************************************************
	 * function name: initCurrent()
	 * The Input: None
	 * The output: None
	 * The Function operation: Sets current node pointer to list's head
	 ***************************************************************************************/
	void initCurrent() {m_currentNode = m_headDummy;}

	/***************************************************************************************
	 * function name: incrmntCurrent()
	 * The Input: None
	 * The output: False if end is reached, True if not
	 * The Function operation: Increments current node pointer. If points at lists end
	 * 			   			   returned value is False, otherwise True
	 ***************************************************************************************/
	bool incrmntCurrent();

	/***************************************************************************************
	 * function name: getCurrentNumber()
	 * The Input: None
	 * The output: Number of student which current node pointer points at.
	 * 	       	   If current node points at no course, NUMBER_ERROR_VAL is returned
	 * The Function operation: Checks if course pointer is NULL. If so, returned NUMBER_ERROR_VAL,
	 *			   			   otherwise returns the number. The method does not change the object
	 ***************************************************************************************/
	int getCurrentNumber() const;

	/***************************************************************************************
	 * function name: getCurrentLecName()
	 * The Input: None
	 * The output: Name of course's lecturer which current node pointer points at.
	 * 	       	   If current node points at no course, NAME_ERROR_VAL is returned
	 * The Function operation: Checks if lecturer pointer is NULL. If so, returned NAME_ERROR_VAL,
	 *			               otherwise returns the name. The method does not change the object
	 ***************************************************************************************/
	string getCurrentLecName() const;

	/***************************************************************************************
	 * function name: getCurrentLecID()
	 * The Input: None
	 * The output: Id of course's lecturer which current node pointer points at.
	 * 	           If current node points at no course, ID_ERROR_VAL is returned
	 * The Function operation: Checks if course pointer is NULL. If so, returned ID_ERROR_VAL,
	 *			               otherwise returns the id of course's lecturer. The method
	 *			               does not change the object
	 ***************************************************************************************/
	int getCurrentLecID() const;

	/***************************************************************************************
	 * function name: searchByKey(const int key)
	 * The Input: Course number to look for
	 * The output: Pointer to course whose number matches given value. If no such course
	 * 			   exists, NULL is returned.
	 * The Function operation: Scans list- if a match is found, a pointer to this course
	 * 			               is returned. If not, NULL is returned. Method does not change
	 * 			               list object or given key
	 ***************************************************************************************/
	Course* searchByKey(const int key) const;

	/***************************************************************************************
	 * function name: searchByIndex(const int index)
	 * The Input: Index to look for
	 * The output: Pointer to course whose index in list matches given value. If no such
	 * 			   student exists, NULL is returned.
	 * The Function operation: Scans list- if a match is found, a pointer to this course
	 * 			   	           is returned. If not, NULL is returned. Method does not change
	 *                         list object or given index
	 ***************************************************************************************/
	Course* searchByIndex(const int index) const ;

	/***************************************************************************************
	 * function name: getCurrentCourse()
	 * The Input: None
	 * The output: Pointer to course that current node points at
	 * The Function operation: Returns pointer to course data attribute of the node which
	 * 			               is pointed by current node pointer. Method does not change
     *                         list object
	 ***************************************************************************************/
	Course* getCurrentCourse() const {return m_currentNode->m_courseData;}
};

#endif
